<template>
  <div class="threeModel">
    <div id="modelBox"></div>

    <button @click="choose" class="btn1">选择</button>
  </div>
</template>

<script>
const SunCalc = require("suncalc")
import borderData from "./housePolygon.json";
import createModel from "./createModel";
import {
  coloring,
  lon2xy,
  GetDistance,
  toMercator
} from "@/utils/common"
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { Line3 } from "three";

import {
  CSS2DObject,
  CSS2DRenderer,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";

import {
  CSS3DObject,
  CSS3DRenderer,
} from "three/examples/jsm/renderers/CSS3DRenderer.js";

var scene, camera, renderer, renderer2, peitaoGroup, floorGroup, roadGroup, houseLineGroup, houseLineTextGroup, directionalLight;
var hUnit = 1;
var mUnit = 1000000


let latitude = 121.4809799194336;
let longitude = 31.226813793182373
const currentTime = new Date();
// 凌晨时分
currentTime.setHours(9, 0, 0, 0);
let times = 0
let timeInterval = 120000; // 2分钟的时间间隔（毫秒）
// 太阳高度
const distance = 100;
let sunX = 100;  // 初始x坐标
let sunY = -100;  // 初始y坐标

export default {
  name: "threeModel",
  data() {
    return {
      borderData: borderData,
      _borderData: [], // 楼房基础数据
      _bounds: [], // 楼房四至
      _center: [], // 楼房中心点
      colors: {
        1: 0xff3333,
        2: 0xff3333,
        3: 0xff3333,
        4: 0xff3333,
        5: 0xff3333,
        6: 0xff3333,
        7: 0xffcc33,
        8: 0xffffff,
        9: 0xffffff,
        10: 0xffffff,
      },
      suns: [
        {
          x: 12.762,
          y: 96.443,
          z: 23.149
        },
        {
          x: 0.67035,
          y: 99.984,
          z: 1.6488
        },
      ]
    };
  },
  mounted() {

    // [121.3711899, 31.2863733],
    //         [121.3712032, 31.2863473]
    borderData.features.map(item => {
      if (item.geometry.type === "MultiLineString") {
        let re = item.geometry.coordinates[0];
        console.log(GetDistance(re[0][1], re[0][0], re[1][1], re[1][0]))
        if (GetDistance(re[0][1], re[0][0], re[1][1], re[1][0]) == "21.81") {
          console.log(re[0][1], re[0][0], re[1][1], re[1][0])
        }
      }

      // console.log(re)

      // item.geometry.coordinates[0].map(re=>{

      // })
    })
    // console.log(GetDistance(31.2878854, 121.371562, 31.2878854, 121.3711899))
    // console.log(GetDistance(31.2863733, 121.3711899, 31.2863473, 121.3712032))
    // console.log(GetDistance(31.2863733, 121.3711899, 31.2863473, 121.3712032))
    this.initContainer(this.borderData);
    this.updateSunPosition()
  },
  methods: {
    // 创建场景
    initContainer(borderData) {
      /*创建场景对象Scene*/
      scene = new THREE.Scene();
      // scene.rotation.set(-45, 0, 0);
      peitaoGroup = new THREE.Group();
      peitaoGroup.name = "peitaoGroup";
      scene.add(peitaoGroup)

      floorGroup = new THREE.Group();
      floorGroup.name = "floorGroup"
      scene.add(floorGroup)

      roadGroup = new THREE.Group();
      roadGroup.name = "roadGroup"
      scene.add(roadGroup)

      houseLineGroup = new THREE.Group();
      houseLineGroup.name = "houseLineGroup"
      scene.add(houseLineGroup)

      houseLineTextGroup = new THREE.Group();
      houseLineTextGroup.name = "houseLineTextGroup"
      scene.add(houseLineTextGroup)
      // AxesHelper：辅助观察的坐标系
      const axesHelper = new THREE.AxesHelper(150);
      scene.add(axesHelper);
      this.initLight()
      this.initCamera()

      this.render();

      //let clock = new THREE.Clock(); //用于更新轨道控制器

      //创建平面
      this.createPlane()

      // 添加楼房楼层平面

      this.addFloors(borderData);

      console.log(scene)
      this.animate();
    },
    createPlane() {
      const geometry = new THREE.PlaneGeometry(1500, 1500);
      const material = new THREE.MeshLambertMaterial({
        color: 0xd9e6ec,
        side: THREE.DoubleSide,
      });
      const plane = new THREE.Mesh(geometry, material);
      plane.position.z = 0;
      scene.add(plane);
      plane.receiveShadow = true; // 平面将接收阴影
    },
    /* 光源设置*/
    initLight() {

      //光源设置
      const ambient = new THREE.AmbientLight(0xcccccc);
      scene.add(ambient);

      //if (this.type !== 1) return;
      directionalLight = new THREE.DirectionalLight(0xcccccc, 1);
      // directionalLight.position.set(100, -100, 100);
      directionalLight.position.set(this.suns[1].x, -this.suns[1].y, -this.suns[1].z);
      scene.add(directionalLight); //平行光

      // 设置产生阴影的光源对象,开启光源阴影的计算功能
      directionalLight.castShadow = true;

      // console.log('阴影相机属性',directionalLight.shadow.camera);
      // 设置三维场景计算阴影的范围
      directionalLight.shadow.camera.left = -200;
      directionalLight.shadow.camera.right = 200;
      directionalLight.shadow.camera.top = 300;
      directionalLight.shadow.camera.bottom = -200;
      directionalLight.shadow.camera.near = 0.5;
      directionalLight.shadow.camera.far = 500;
      directionalLight.shadow.mapSize.set(2048, 2048);

      // 模糊弱化阴影边缘
      directionalLight.shadow.radius = 3;
      // 可视化平行光阴影对应的正投影相机对象
      const cameraHelper = new THREE.CameraHelper(
        directionalLight.shadow.camera
      );
      scene.add(cameraHelper);


      // model
      // var loader = new FBXLoader();
      // loader.load('https://xfbd.oss-cn-hangzhou.aliyuncs.com/svg/sun_spring.fbx', function(object) {

      // 	//播放动画
      // 	//  mixer = new THREE.AnimationMixer( object );
      // 	//  var action = mixer.clipAction( object.animations[ 0 ] );
      // 	//  action.play();
      // 	//渲染阴影
      // 	// object.traverse( function ( child ) {
      // 	//
      // 	//     if ( child.isMesh ) {
      // 	//
      // 	//         child.castShadow = true;
      // 	//         child.receiveShadow = true;
      // 	//
      // 	//     }
      // 	//
      // 	// } );
      // 	object.scale.set(0.01, 0.01, 0.01); //修改模型缩放系数(x,y,z)
      // 	scene.add(object);



      // });
    },
    initCamera() {
      /**
       * 相机设置
       */
      var width = window.innerWidth; //窗口宽度
      var height = window.innerHeight; //窗口高度
      var k = width / height; //窗口宽高比
      var s = 1500; //三维场景显示范围控制系数，系数越大，显示的范围越大
      //创建相机对象
      camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        10000
      );
      camera.position.set(300, -300, 300);
      camera.up.set(0, 0, 1);
      camera.lookAt(0, 0, 0);
    },

    animate() {
      // if (times < 180) {
      //   this.updateSunPosition();
      // }

      // if (directionalLight.position.x <= -100) {
      //   directionalLight.position.x = 100;
      // }
      // directionalLight.position.x = directionalLight.position.x - 1;



      renderer.render(scene, camera);
      renderer2.render(scene, camera);
      requestAnimationFrame(this.animate);
    },
    updateSunPosition() {
      if (times >= 180) {
        currentTime.setHours(9, 0, 0, 0);
        times = 0
      }
      // const sunPosition = SunCalc.getPosition(currentTime, latitude, longitude);
      // console.log(sunPosition)
      // const sunAzimuth = sunPosition.azimuth * (180 / Math.PI);
      // const sunAltitude = sunPosition.altitude * (180 / Math.PI);

      // console.log("sunAzimuth")
      // console.log(sunAzimuth)


      // console.log("sunAltitude")
      // console.log(sunAltitude)

      // const theta = (90 - sunAltitude) * (Math.PI / 180);
      // const phi = (-sunAzimuth + 180) * (Math.PI / 180); // 考虑太阳在地平线以下的情况
      // const r = 200;
      // const x = r * Math.sin(theta) * Math.cos(phi);
      // const y = r * Math.cos(theta);
      // const z = r * Math.sin(theta) * Math.sin(phi);

      // // 时间推移
      // currentTime.setTime(currentTime.getTime() + timeInterval);
      // times += 1;
      // // 因为太阳是从底部出来，所以数据去反就好了;

      // console.log(Math.abs(x), Math.abs(y), Math.abs(z))
      // directionalLight.position.set(Math.abs(x), Math.abs(y), Math.abs(z));

      const sun = new THREE.Vector3();
      const phi = THREE.MathUtils.degToRad(90 - 22);
      const theta = THREE.MathUtils.degToRad(180 - 119.62);

      sun.setFromSphericalCoords(1, phi, theta);
      console.log("sun")
      // console.log(sun.multiplyScalar(300))
      console.log(sun)
      sun.multiplyScalar(100);
      directionalLight.position.x = sun.x;
      directionalLight.position.y = -sun.y;
      directionalLight.position.z = sun.z;


    },
    render() {



      let dom = document.getElementById("modelBox");
      /**
       * 创建渲染器对象
       */
      renderer = new THREE.WebGLRenderer({
        antialias: true,
      });
      renderer.setPixelRatio(window.devicePixelRatio); //防止输出模糊
      renderer.setSize(window.innerWidth, window.innerHeight);
      dom.appendChild(renderer.domElement);
      renderer.setClearColor(new THREE.Color(0xcce0ff))
      renderer.shadowMap.enabled = true;

      var controls = new OrbitControls(camera, renderer.domElement);
      controls.target = new THREE.Vector3(0, 0, 0); //控制焦点
      controls.autoRotate = false; //将自动旋转关闭

      //设置dom元素的渲染
      renderer2 = new CSS3DRenderer();
      renderer2.setSize(window.innerWidth, window.innerHeight);
      renderer2.domElement.style.position = "absolute";
      renderer2.domElement.style.top = 0;
      dom.appendChild(renderer2.domElement);
      var controls2 = new OrbitControls(camera, renderer2.domElement);
      controls2.target = new THREE.Vector3(0, 0, 0); //控制焦点
      controls2.autoRotate = false; //将自动旋转关闭
    },
    // 添加楼群
    addFloors(data) {
      // 数据处理/基础数据计算
      this._dataAnalysis(data);
      this._getModelBounds();
      this._getModelCenter();
      this._dataAnalysisAll();

      // 添加楼层
      this._borderData.forEach((res) => {
        if (res.type === "building") {
          this.createFloor(res);
        }
        // else if (res.type === "road") {
        //   console.log("进入road");
        //   this.createRoad(res);
        // } else if (res.type === "peitao") {
        //   this.createPeitao(res);
        // } else 
        // if (res.geometryType === "MultiLineString") {
        //   console.log(res);
        //   this.createHouseLine(res);
        // }
      });
    },
    //创建路的平面
    createRoadShape(data) {
      var shape = new THREE.Shape();
      data.map((item, index) => {
        if (index === 0) {
          item.forEach((e, i) => {
            if (i === 0) {
              shape.moveTo(...e);
            } else {
              shape.lineTo(...e);
            }
          });
        } else {
          const path = new THREE.Path();
          item.forEach((e, i) => {
            if (i === 0) {
              path.moveTo(...e);
            } else {
              path.lineTo(...e);
            }
          });
          shape.holes.push(path);
        }
      });

      return shape;
    },
    //添加线
    createHouseLine(data) {
      if (data.points) {
        const points = [];
        var pos1 = null;
        var pos2 = null;
        data.points.map((item, index) => {
          if (index === 0) {
            pos1 = new THREE.Vector3(item[0], item[1], 0);
          } else if (index === 1) {
            pos2 = new THREE.Vector3(item[0], item[1], 0);
          }
          points.push(new THREE.Vector3(item[0], item[1], 0));
        });
        const material = new THREE.LineBasicMaterial({ color: 0x3f96f1 });
        const geometry = new THREE.BufferGeometry().setFromPoints(points);
        const line = new THREE.Line(geometry, material);
        line.position.z = 1;
        line.userData = data;
        houseLineGroup.add(line);

        var distance = pos1.distanceTo(pos2).toFixed(0) * 1;
        console.log(distance);
        var center = new THREE.Vector3();
        var linePath = new Line3(pos1, pos2);
        linePath.getCenter(center);
        this.addLineText(distance + "", center, data);
      }
    },
    //添加楼间线段文字

    //添加标注
    addLineText(distance, center, data) {
      const element = document.createElement("div");
      var fontSize = 16;
      element.className = "distance";
      element.innerText = `${distance}`;
      const object = new CSS3DObject(element);
      object.position.x = center.x - (distance.length * fontSize) / 2;
      object.position.y = center.y;
      object.position.z = center.z;
      object.userData = data
      houseLineTextGroup.add(object);
    },
    //添加配套
    createPeitao(data) {
      let shape = this.createShape(data.points[0]);
      for (let i = 0; i < data.floor; i++) {
        let mesh = this.createPolyline(shape, i, data.high, 0xffffff, data);
        peitaoGroup.add(mesh);
      }
    },
    //添加路面
    createRoad(data) {
      let shape = this.createRoadShape(data.points);
      var geometry = new THREE.ShapeGeometry(shape);
      var cubeMaterial = new THREE.MeshBasicMaterial({
        color: 0xededed,
        // transparent: true,
        opacity: 1,
        side: THREE.DoubleSide, // 强制双面
      });
      let mesh = new THREE.Mesh(geometry, cubeMaterial);
      mesh.position.z = 0;
      // 设置接收阴影的投影面
      mesh.receiveShadow = true;
      roadGroup.add(mesh);
    },
    // 添加单个楼
    createFloor(data) {
      // 新建楼房组
      let shape = this.createShape(data.points[0]);
      for (let i = 0; i < data.floor; i++) {
        let mesh = this.createPolyline(
          shape,
          i,
          data.high,
          this.colors[parseInt(data.sun_q1.split(",")[i])],
          data
        );
        floorGroup.add(mesh);
      }
      // if (floorGroup.children[0]) {
      //   var center = this.getCenterPoint(floorGroup.children[floorGroup.children.length - 1]);
      //   center.z = (data.floor + 1) * data.high * hUnit;
      //   const element = document.createElement("div");
      //   element.className = "tag";
      //   element.innerText = `${data.building_n}`;
      //   const object = new CSS3DObject(element);
      //   //object.visible = true;
      //   //缩放比例
      //   object.scale.set(2, 2, 2);
      //   //指定摆放位置
      //   object.position.copy(center);
      //   object.rotation.y = 0;
      //   object.rotation.z = 0;
      //   object.rotation.x = Math.PI / 2;
      //   floorGroup.add(object);
      // }
    },
    //获取楼栋中点
    getCenterPoint(mesh) {
      var middle = new THREE.Vector3();
      var geometry = mesh.geometry;

      geometry.computeBoundingBox();

      middle.x = (geometry.boundingBox.max.x + geometry.boundingBox.min.x) / 2;
      middle.y = (geometry.boundingBox.max.y + geometry.boundingBox.min.y) / 2;
      middle.z = (geometry.boundingBox.max.z + geometry.boundingBox.min.z) / 2;

      return middle;
    },
    // 数据转换
    _dataAnalysis(borderData) {
      let data = [];
      borderData.features.forEach((res) => {
        if (
          res.geometry.type === "polygon" ||
          res.geometry.type === "MultiLineString"
        ) {
          res.geometry.coordinates.forEach((r) => {
            // 将度转换为米
            r = r.map((re) => {
              // return [
              // 	(re[0] * mUnit).toFixed(0) * 1,
              // 	(re[1] * mUnit).toFixed(0) * 1,
              // ];
              let lnglat = lon2xy(parseFloat(re[0]), parseFloat(re[1]))
              return [
                lnglat.x,
                lnglat.y,
              ];
            });
            data.push({
              ...res.properties,
              geometryType: res.geometry.type,
              points: r,
            });
          });
        } else if (res.geometry.type === "MultiPolygon") {
          let pointArrs = [];
          res.geometry.coordinates.forEach((r) => {
            // 将度转换为米
            r.map((re) => {
              let pr = [];
              re.map((ree) => {
                // pr.push([
                // 	(ree[0] * mUnit).toFixed(0) * 1,
                // 	(ree[1] * mUnit).toFixed(0) * 1,
                // ]);
                let lnglat = lon2xy(parseFloat(ree[0]), parseFloat(ree[
                  1]))
                pr.push([
                  lnglat.x,
                  lnglat.y,
                ]);
              });
              pointArrs.push(pr);
            });
          });
          data.push({
            ...res.properties,
            geometryType: res.geometry.type,
            points: pointArrs,
          });
        }
      });
      this._borderData = data;
    },
    // 获取模型四至
    _getModelBounds() {
      // 四至： 上右下左
      let bounds = [0, 0, 0, 0];
      // 所有点数组
      let pointArr = [];
      // 所有点经度数组
      let pointLonArr = [];
      // 所有点纬度数组
      let pointLatArr = [];
      // 获取所有点数组
      this._borderData.forEach((res) => {
        if (
          res.geometryType === "polygon" ||
          res.geometryType === "MultiLineString"
        ) {
          pointArr = pointArr.concat(res.points);
        } else if (res.geometryType === "MultiPolygon") {
          res.points.map((item) => {
            pointArr = pointArr.concat(item);
          });
        }
      });
      // 获取经度、纬度数组
      pointArr.forEach((res) => {
        pointLonArr.push(res[0]);
        pointLatArr.push(res[1]);
      });
      // 获取四至
      bounds = [
        Math.max(...pointLatArr),
        Math.min(...pointLonArr),
        Math.min(...pointLatArr),
        Math.max(...pointLonArr),
      ];
      this._bounds = bounds;
    },
    // 获取模型中心点
    _getModelCenter() {
      let center = [
        (this._bounds[1] + this._bounds[3]) / 2,
        (this._bounds[0] + this._bounds[2]) / 2,
      ];
      this._center = center;
    },
    // 数据转换2-将数据移动至原点
    _dataAnalysisAll() {
      this._borderData.forEach((res) => {
        if (
          res.geometryType === "polygon" ||
          res.geometryType === "MultiLineString"
        ) {
          res.points.forEach((re) => {
            re[0] = re[0] - this._center[0];
            re[1] = re[1] - this._center[1];
          });
        } else if (res.geometryType === "MultiPolygon") {
          res.points.forEach((re) => {
            re.map((ree) => {
              ree[0] = ree[0] - this._center[0];
              ree[1] = ree[1] - this._center[1];
            });
          });
        }
      });
    },
    // 创建平面集合
    createShape(data) {
      var shape = new THREE.Shape();
      data.forEach((e, i) => {
        if (i === 0) {
          shape.moveTo(...e);
        } else {
          shape.lineTo(...e);
        }
      });
      return shape;
    },
    // 创建透明平面
    createPolyline(shape, h, high, color = 0xffffff, userData = {}) {
      var geometry = new THREE.ExtrudeGeometry(shape, {
        depth: high * hUnit,
      });
      var cubeMaterial = new THREE.MeshLambertMaterial({
        color: color,
        // transparent: true,
        opacity: 1,
        //side: THREE.DoubleSide, // 强制双面
      });
      var mesh = new THREE.Mesh(geometry, cubeMaterial);
      mesh.castShadow = true;
      mesh.receiveShadow = true;
      mesh.position.z = h * high * hUnit;
      mesh.userData = {
        ...userData,
        color: color
      };
      // 长方体作为EdgesGeometry参数创建一个新的几何体
      const edges = new THREE.EdgesGeometry(geometry);
      const edgesMaterial = new THREE.LineBasicMaterial({
        color: 0xcccccc,
      });
      const line = new THREE.LineSegments(edges, edgesMaterial);
      mesh.add(line);
      return mesh;
    },

    choose(num = "2") {
      scene.getObjectByName('floorGroup').children.map(item => {
        if (item.userData.type === "building" && item.userData.building_n == num) {
          //设置材质颜色
          item.material.color.set(new THREE.Color(0x42b983))
          item.material.opacity = 0.8
        }
      })

      scene.getObjectByName('houseLineGroup').children.map(item => {
        if (item.userData.lou && item.userData.lou.indexOf(num > -1)) {
          //设置材质颜色
          console.log(item)
          item.material.color.set(new THREE.Color(0xff6600))
        }
      })

      scene.getObjectByName('houseLineTextGroup').children.map(item => {
        if (item.userData.lou && item.userData.lou.indexOf(num > -1)) {
          //设置材质颜色
          console.log(item)
          item.element.style.color = "#ff6600"
          item.element.style.background = "#ffffff"
        }
      })
      console.log(scene.getObjectByName('houseLineTextGroup'))
    }
  },
};
</script>

<style scoped>
.threeModel {
  /* // background: url("../../../assets/images/loop.png") no-repeat;
  // background-size: 100% 100%; */
  width: 100%;
  height: 100%;
  position: relative;
}

#modelBox {
  width: 100%;
  height: 100%;
  background: rgb(217, 230, 236);
}

.btn1 {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
}
</style>
